今天先看原始碼的部分,Demo 那個有趣的特效,明天來實做看看~
官方 Demo:https://vueuse.org/core/useParallax/#useparallax
// src/compositions/useParallax.js
export function useParallax(target, options = {}) {
const {
deviceOrientationTiltAdjust = i => i,
deviceOrientationRollAdjust = i => i,
mouseTiltAdjust = i => i,
mouseRollAdjust = i => i,
window = defaultWindow,
} = options
// ...略
}
roll、tilt 稍後會看到,現在先不理他。
target
:要觸發視差效果的 elementdeviceOrientationTiltAdjust = i => i
:裝置的 tilt 值幅度,EX:deviceOrientationTiltAdjust: (i: number) => 20 * i
是 20 倍。deviceOrientationRollAdjust = i => i,
:裝置的 roll 值幅度。mouseTiltAdjust = i => i,
:滑鼠事件的 tilt 值幅度。mouseRollAdjust = i => i,
:滑鼠事件的 roll 值幅度。// src/compositions/useParallax.js
export function useParallax(target, options = {}) {
// ...略
return { roll, tilt, source }
}
roll
tilt
source
:觸發的事件類型。deviceOrientation 或是 mouse。mouse 跟 deviceOrientation 觸發的 code 可以完全分開看,先從 mouse 開始~
// src/compositions/useParallax.js
import { computed, reactive } from 'vue'
import { useDeviceOrientation } from '@/compositions/useDeviceOrientation'
import { useMouseInElement } from '@/compositions/useMouseInElement'
import { useScreenOrientation } from '@/compositions/useScreenOrientation'
import { defaultWindow } from '@/helper'
export function useParallax(target, options = {}) {
const {
deviceOrientationTiltAdjust = i => i,
deviceOrientationRollAdjust = i => i,
mouseTiltAdjust = i => i,
mouseRollAdjust = i => i,
window = defaultWindow,
} = options
const orientation = reactive(useDeviceOrientation({ window }))
const screenOrientation = reactive(useScreenOrientation({ window }))
const {
elementX: x,
elementY: y,
elementWidth: width,
elementHeight: height,
} = useMouseInElement(target, { handleOutside: false, window })
const source = computed(() => {
if (orientation.isSupported
&& ((orientation.alpha != null && orientation.alpha !== 0) || (orientation.gamma != null && orientation.gamma !== 0))
) {
return 'deviceOrientation'
}
return 'mouse'
})
const roll = computed(() => {
if (source.value === 'deviceOrientation') {
// deviceOrientation source
}
else {
// (y.value - height.value / 2) 這段是為了讓滑鼠在畫面中央時,roll 值為 0
// 除以 height.value 是為了換算成百分比,也因為前面有除 2,所以這邊會是 -0.5 ~ 0.5
// 負號是因為滑鼠往下滑時,y 值會變大,但 roll 值要變小
const value = -(y.value - height.value / 2) / height.value
return mouseRollAdjust(value)
}
})
const tilt = computed(() => {
if (source.value === 'deviceOrientation') {
// deviceOrientation source
}
else {
const value = (x.value - width.value / 2) / width.value
return mouseTiltAdjust(value)
}
})
return { roll, tilt, source }
}
可以看到 source computed 回傳 deviceOrientation
or mouse
,不過我不確定為什麼要同時拿 orientation.alpha & orientation.gamma 來判斷就是了 XD,以瀏覽器來說,這兩個都是 null。
計算部分可以參考 roll computed 中的註解,tilt 的話可以套用 roll 的算法,只是從 y 軸的計算變成 x 軸的計算,概念一樣。
跟上面 mouse 觸發的程式碼,只有在 computed 有差異:
// src/compositions/useParallax.js
// ... 略
const roll = computed(() => {
if (source.value === 'deviceOrientation') {
let value
switch (screenOrientation.orientation) {
case 'landscape-primary':
value = orientation.gamma / 90
break
case 'landscape-secondary':
value = -orientation.gamma / 90
break
case 'portrait-primary':
value = -orientation.beta / 90
break
case 'portrait-secondary':
value = orientation.beta / 90
break
default:
value = -orientation.beta / 90
}
return deviceOrientationRollAdjust(value)
}
// ...略
})
const tilt = computed(() => {
if (source.value === 'deviceOrientation') {
let value
switch (screenOrientation.orientation) {
case 'landscape-primary':
value = orientation.beta / 90
break
case 'landscape-secondary':
value = -orientation.beta / 90
break
case 'portrait-primary':
value = orientation.gamma / 90
break
case 'portrait-secondary':
value = -orientation.gamma / 90
break
default:
value = orientation.gamma / 90
}
return deviceOrientationTiltAdjust(value)
}
// ...略
})
關於 landscape-primary
、landscape-secondary
、portrait-primary
、portrait-secondary
裝置方向以及gamma
、beta
,可以參考昨天的圖文解釋比較清楚~
一樣拿 roll 來看,可以看到根據裝置方向的不同,會分別拿 gamma、beta 來做計算。這邊在看的時候卡了一陣子,後來發現關鍵在於,不管設備如何換方向,內部坐標系都不會變。也就是說,當我們在 portrait-primary 方向以 x 軸為主軸,前後翻轉裝置,gamma 值會跟著變,這時候把方向往順時針 90 度轉成 landscape-primary,我們想要做跟剛剛一樣的前後翻轉時,主軸變成裝置內部坐標系的 y 軸,也因為是繞著 y 軸轉,所以這時候跟著改變的並不是剛剛的 gamma 值,而是 bata 值。
所以這邊的計算,關於方向或是正負號的判斷,可以讓我們裝置在四個不同的方向使用這個 API,都可以拿到一樣的結果。
GitHub PR:https://github.com/RhinoLee/30days_vue/pull/15
useParallax 的 source code 就到這邊告一段落,這兩天看這些跟空間有關的東西,頭都痛了起來 XD
明天會想看 useParallax 官方 Demo 的那個特效是怎麼透過 useParallax API 實作出來的~